Finding a rich text phrase and replacing it with different rich text

I'm very new to DOORS DXL, so I apologize in advance. I'm trying to write a very simple script to find a phrase of rich text with possible formatting and replace it with another phrase of rich text. The problem is that if the phrase I'm looking for contains any rich text formatting I cannot find it, in my instance a bolded NOT. Any help and tips are most appreciated and I've attached my script below(mostly stolen from another thread). Thanks!

Module m = current
Object o = current

Buffer bodyText = create()
Buffer newText = create()

int length, offset, replaceCount
replaceCount= 0

string phraseToReplace, completionInfo
phraseToReplace = " not be inhibited"

//for o in m do
//{
newText = ""
bodyText = richText o."_Expected Results"
print tempStringOf bodyText
if (findRichText(tempStringOf bodyText, phraseToReplace, offset, length, false))
{
combine (newText, bodyText, 0, offset-1)
newText += " operate {\\b normally}"
combine (newText, bodyText, offset+length)
o."_Expected Results" = richText tempStringOf newText
replaceCount ++
}
//}

completionInfo = "Done. " replaceCount " items were replaced."
print completionInfo

delete newText
delete bodyText
NickPernsteiner - Fri Jan 06 10:40:26 EST 2012

Re: Finding a rich text phrase and replacing it with different rich text
smarti.sj - Fri Jan 06 12:20:10 EST 2012

Hi Nick

I think you did fine - but if I understand this correctly - you have comment about an occurence of "NOT" in your "_Expected Results" attribute but your script is looking for "not be inhibited". Your script works fine for the current object containing a bold "not be inhibited", as you have the mod loop commented out.

Sara

Re: Finding a rich text phrase and replacing it with different rich text
NickPernsteiner - Fri Jan 06 13:00:58 EST 2012

smarti.sj - Fri Jan 06 12:20:10 EST 2012
Hi Nick

I think you did fine - but if I understand this correctly - you have comment about an occurence of "NOT" in your "_Expected Results" attribute but your script is looking for "not be inhibited". Your script works fine for the current object containing a bold "not be inhibited", as you have the mod loop commented out.

Sara

Thanks for your help Sara.

Unfortunately, I probably should have explained my comment about "NOT" a bit more. My phrases of "NOT be inhibited" will replace if the NOT is not bolded, if the NOT in the phrase is bolded they won't replace. When I print the rich text string of my phrase I get "\b NOT \b0 be inhibited". I've tried some roundabout attempts, to not success.

Re: Finding a rich text phrase and replacing it with different rich text
llandale - Mon Jan 09 17:30:08 EST 2012

The following is not quite a complete solution. Maybe one of the rich-text experienced folks will jump in here with something far more elegant or at least clean up my mess.

I "solved" this quite a long time ago but never used it (and never used Rich-Text again) and never upgraded it to use the vastly superior Buffers over strings. The considerations that lead to the solution are these:

  • You need to find your search string in the RAW version of the rich text.
  • You need to do processing on your rich-text based on start and offset values relative to that raw-text.
  • You need a crystal ball to tell which rich-text functions deal with raw-text offsets (instead of the intuitive rich-text offsets); the manual doesn't say. Or I can tell you, its cutRichText().
  • There were issues when the search string contains actual rich-text markup, such as changing "never \b the" to something else; which I think this solution resolved but I don't recall the details.


You, or someone, will..

 

  • ..need to write your own fGetOffset() function. Mine's probably 4x as complicated as it needs to be and I'm embarrassed; although it works without any memory leak.
  • ..definately want to convert these functions to use Buffers.
  • ..want to replace fStripRT() with the plainText() function; I wrote that before plainText() was available.
  • ..replace fConCat() with straight contatenation; or clever Buffer combines.

 

//*****************
string    fExtractRT(string TextRich, int StartLoc, EndLoc, LenRaw)
{     // Extract the portion of the Rich Text string in the TextRich
        //   as identified by the starting and ending locations.
        // Preserve the TextRich's RichText markup
 
        // StartLoc and EndLoc and LenRaw MUST be relative to the equivalent RAW text,
        //    perhaps by calling Loc = fGetOffset(TextRaw, SearchString).
 
        // Strategy: only mechanism for extracting out of a rich text chunk is using cutRichText().
        //      Thus, we cut the part after EndLoc, then cut the part before StartLoc, leaving what we want.
 
        string  OutText
        if (EndLoc   < StartLoc      or
            EndLoc   > LenRaw        or
            StartLoc < 0)            return("")    // Program Input Error
 
        if (EndLoc == LenRaw)
             OutText = TextRich
        else OutText = cutRichText(TextRich, EndLoc+1, LenRaw)          // Strip Ending
        // print ":::: Extract, TextRich, OutText = >>" TextRich "<<<   >>>" OutText "<<\n"
        if (StartLoc > 0)
             OutText = cutRichText(OutText, 0,  StartLoc-1)             // Strip Beginning
        // print ">>>>>> Extract: In/Start/End/Tot/Out = >>>" TextRich "<<<  " StartLoc "  " //-
        //             EndLoc "  " LenTotal " >>>" OutText "<<<\n"
        return(OutText)
}     // end fExtractRT()
 
//-------------------
string  fExtractRT(string TextRich, int StartLoc, EndLoc)
{     // Overloaded, doesn't need input Raw Text Length
        int     LenText = length(TextRich)      // Use rich text length, doesn't matter.
        return(fExtractRT(TextRich, StartLoc, EndLoc, LenText))
}     // end fExtractRT()
 
//*********************
string  fStripRT(string InString)
{     // Legacy
        return(plainText(InString))
}     // end fStripRT(string)
 
//*********************
void    fStripRT(Buffer &in_buf)
{     // Legacy
        // in_buf = plainText(stringOf(in_buf))
        in_buf = plainText(tempStringOf(in_buf))
}     // end fStripRT(Buffer)
 
//****************************************************
string  fReplaceRawText(string InRich, StringFrom, StringTo, bool MatchCase)
{     // Replace all occurrences of the raw StringFrom to the raw StringTo in the
        //    Rich Text string InRich.  RichText markup in InRich is ignored but preserved.
        // Note: Even for simple RichText strings, this function returns a very large string
        //    featuring lots of RTF header info.  User may want to issue "removeUnlistedRichText"
        //    after calling this function.
        // Developers Note: This is a little tricky since some StringFrom may be part of the Markup,
        //    but needs to be ignored.
        // Strategy: Get the Raw representation of the string.  Search for the StringFrom.
        //    if found, build a new RichText string composed of the part before the found location,
        //    the StringTo, and the part after the found location.  That last part must be
        //    recursively searched before its appended.
 
 
        if (null InRich or null StringFrom) return("")
 
        string  InRaw, FirstPart, LastPart
        int     LenFrom, LocFrom, LenRaw
 
        InRaw   = fStripRT(InRich)
        LocFrom = fGetOffset(InRaw, StringFrom, MatchCase)
        if (LocFrom < 0) return(InRich)      // StringFrom not found, nothing to do
        LenRaw  = length(InRaw)
        LenFrom = length(StringFrom)
 
        if (LocFrom == 0)
             FirstPart = ""   // Found in the first position.
        else FirstPart = fExtractRT(InRich, 0, LocFrom-1, LenRaw)
        if (LocFrom+LenFrom-1 >= LenRaw)
             LastPart  = ""   // Found as last position(s) in the string
        else
        {    LastPart = fExtractRT(InRich, LocFrom+LenFrom, LenRaw-1, LenRaw)
             LastPart = fReplaceRawText(LastPart, StringFrom, StringTo, MatchCase)      // ** RECURSIVE **
        }
//      print "**LenRich/LenRaw =\t" (length(InRich)) "\t" LenRaw "\n"
//      print "**LocFrom   =\tSearching for \t<">, found at \t" LocFrom   "\n"
//      print "**FirstPart =\t" FirstPart "\n"
//      print "**LastPart  =\t" LastPart  "\n"
        return(fConCat(FirstPart, StringTo, LastPart))
}    // end fReplaceRawText()


Good luck.

-Louie

There is another issue I resolved when replacing raw text but did not include in the above rich text. That's when the from string is a sub-set of the replace string; for me in the stone age that was when I replaced all references of "My Company" to "My Company Inc" in the all requirements; resulting in "My Company Inc Inc Inc" as time went by and proving managers have no sense of humor. The solution was recognizing the sub-set existance, then pain stakingly search for the replace string when the search string was found, and NOT doing any replace when the replace string already existed. Yuuuuuck. Just searched, it seems I lost that solution.

Re: Finding a rich text phrase and replacing it with different rich text
NickPernsteiner - Wed Jan 11 12:25:13 EST 2012

llandale - Mon Jan 09 17:30:08 EST 2012

The following is not quite a complete solution. Maybe one of the rich-text experienced folks will jump in here with something far more elegant or at least clean up my mess.

I "solved" this quite a long time ago but never used it (and never used Rich-Text again) and never upgraded it to use the vastly superior Buffers over strings. The considerations that lead to the solution are these:

  • You need to find your search string in the RAW version of the rich text.
  • You need to do processing on your rich-text based on start and offset values relative to that raw-text.
  • You need a crystal ball to tell which rich-text functions deal with raw-text offsets (instead of the intuitive rich-text offsets); the manual doesn't say. Or I can tell you, its cutRichText().
  • There were issues when the search string contains actual rich-text markup, such as changing "never \b the" to something else; which I think this solution resolved but I don't recall the details.


You, or someone, will..

 

  • ..need to write your own fGetOffset() function. Mine's probably 4x as complicated as it needs to be and I'm embarrassed; although it works without any memory leak.
  • ..definately want to convert these functions to use Buffers.
  • ..want to replace fStripRT() with the plainText() function; I wrote that before plainText() was available.
  • ..replace fConCat() with straight contatenation; or clever Buffer combines.

 

//*****************
string    fExtractRT(string TextRich, int StartLoc, EndLoc, LenRaw)
{     // Extract the portion of the Rich Text string in the TextRich
        //   as identified by the starting and ending locations.
        // Preserve the TextRich's RichText markup
 
        // StartLoc and EndLoc and LenRaw MUST be relative to the equivalent RAW text,
        //    perhaps by calling Loc = fGetOffset(TextRaw, SearchString).
 
        // Strategy: only mechanism for extracting out of a rich text chunk is using cutRichText().
        //      Thus, we cut the part after EndLoc, then cut the part before StartLoc, leaving what we want.
 
        string  OutText
        if (EndLoc   < StartLoc      or
            EndLoc   > LenRaw        or
            StartLoc < 0)            return("")    // Program Input Error
 
        if (EndLoc == LenRaw)
             OutText = TextRich
        else OutText = cutRichText(TextRich, EndLoc+1, LenRaw)          // Strip Ending
        // print ":::: Extract, TextRich, OutText = >>" TextRich "<<<   >>>" OutText "<<\n"
        if (StartLoc > 0)
             OutText = cutRichText(OutText, 0,  StartLoc-1)             // Strip Beginning
        // print ">>>>>> Extract: In/Start/End/Tot/Out = >>>" TextRich "<<<  " StartLoc "  " //-
        //             EndLoc "  " LenTotal " >>>" OutText "<<<\n"
        return(OutText)
}     // end fExtractRT()
 
//-------------------
string  fExtractRT(string TextRich, int StartLoc, EndLoc)
{     // Overloaded, doesn't need input Raw Text Length
        int     LenText = length(TextRich)      // Use rich text length, doesn't matter.
        return(fExtractRT(TextRich, StartLoc, EndLoc, LenText))
}     // end fExtractRT()
 
//*********************
string  fStripRT(string InString)
{     // Legacy
        return(plainText(InString))
}     // end fStripRT(string)
 
//*********************
void    fStripRT(Buffer &in_buf)
{     // Legacy
        // in_buf = plainText(stringOf(in_buf))
        in_buf = plainText(tempStringOf(in_buf))
}     // end fStripRT(Buffer)
 
//****************************************************
string  fReplaceRawText(string InRich, StringFrom, StringTo, bool MatchCase)
{     // Replace all occurrences of the raw StringFrom to the raw StringTo in the
        //    Rich Text string InRich.  RichText markup in InRich is ignored but preserved.
        // Note: Even for simple RichText strings, this function returns a very large string
        //    featuring lots of RTF header info.  User may want to issue "removeUnlistedRichText"
        //    after calling this function.
        // Developers Note: This is a little tricky since some StringFrom may be part of the Markup,
        //    but needs to be ignored.
        // Strategy: Get the Raw representation of the string.  Search for the StringFrom.
        //    if found, build a new RichText string composed of the part before the found location,
        //    the StringTo, and the part after the found location.  That last part must be
        //    recursively searched before its appended.
 
 
        if (null InRich or null StringFrom) return("")
 
        string  InRaw, FirstPart, LastPart
        int     LenFrom, LocFrom, LenRaw
 
        InRaw   = fStripRT(InRich)
        LocFrom = fGetOffset(InRaw, StringFrom, MatchCase)
        if (LocFrom < 0) return(InRich)      // StringFrom not found, nothing to do
        LenRaw  = length(InRaw)
        LenFrom = length(StringFrom)
 
        if (LocFrom == 0)
             FirstPart = ""   // Found in the first position.
        else FirstPart = fExtractRT(InRich, 0, LocFrom-1, LenRaw)
        if (LocFrom+LenFrom-1 >= LenRaw)
             LastPart  = ""   // Found as last position(s) in the string
        else
        {    LastPart = fExtractRT(InRich, LocFrom+LenFrom, LenRaw-1, LenRaw)
             LastPart = fReplaceRawText(LastPart, StringFrom, StringTo, MatchCase)      // ** RECURSIVE **
        }
//      print "**LenRich/LenRaw =\t" (length(InRich)) "\t" LenRaw "\n"
//      print "**LocFrom   =\tSearching for \t<">, found at \t" LocFrom   "\n"
//      print "**FirstPart =\t" FirstPart "\n"
//      print "**LastPart  =\t" LastPart  "\n"
        return(fConCat(FirstPart, StringTo, LastPart))
}    // end fReplaceRawText()


Good luck.

-Louie

There is another issue I resolved when replacing raw text but did not include in the above rich text. That's when the from string is a sub-set of the replace string; for me in the stone age that was when I replaced all references of "My Company" to "My Company Inc" in the all requirements; resulting in "My Company Inc Inc Inc" as time went by and proving managers have no sense of humor. The solution was recognizing the sub-set existance, then pain stakingly search for the replace string when the search string was found, and NOT doing any replace when the replace string already existed. Yuuuuuck. Just searched, it seems I lost that solution.

Thanks Louie.

That is similar to the approach I ended up using except mine is not generic or elegant in the slightest. I ended up using plain text and since I knew what my RTF was most of the time I included that in my find string and then manhandled what was left. I may try to implement your approach if I have time.

Out of curiosity, how did you get away with never using rich-text again?

Re: Finding a rich text phrase and replacing it with different rich text
llandale - Wed Jan 11 14:55:08 EST 2012

NickPernsteiner - Wed Jan 11 12:25:13 EST 2012
Thanks Louie.

That is similar to the approach I ended up using except mine is not generic or elegant in the slightest. I ended up using plain text and since I knew what my RTF was most of the time I included that in my find string and then manhandled what was left. I may try to implement your approach if I have time.

Out of curiosity, how did you get away with never using rich-text again?

I meant I haven't written DXL to deal cleverly with rich-text. That really isn't true but it makes the original post flow better. ;)

-Louie